package utils

import (
	"encoding/binary"
	"errors"
	"fmt"
	"net"
	"net/url"
	"os/exec"
	"runtime"
	"strconv"
	"time"

	"gitee.com/love_bass/go-ping/ping"
)

// IsValidIP
// 检测IP地址是否合法
func IsValidIP(ipAddr string) bool {
	return net.ParseIP(ipAddr) != nil
}

// IsValidPort
// 检测端口是否合法
func IsValidPort(port string) (int, error) {
	p, err := strconv.Atoi(port)
	if err != nil {
		return 0, fmt.Errorf("port conversion error: %v", err)
	}
	if p < 1 || p > 65535 {
		return 0, fmt.Errorf("port number out of range: %d", p)
	}
	return p, nil
}

// IsValidURL
// 检测给定字符串是否是一个合法的URL。
func IsValidURL(u string) bool {
	// 尝试解析URL
	parsed, err := url.ParseRequestURI(u)
	if err != nil {
		return false // 解析失败意味着这不是一个合法的URL
	}

	// 判断解析后的URL是否包含Host字段，常用来判断URL是否合法
	return parsed.Scheme != "" && parsed.Host != ""
}

// PingUseCommand 使用系统ping命令
// 对目的地址发起ping检测icmp是否通畅（只支持ipv4）
func PingUseCommand(ipAddr string) (bool, error) {
	var cmd *exec.Cmd

	// 根据操作系统选择不同的ping命令和参数
	switch runtime.GOOS {
	case "windows":
		// Windows的ping命令是 "ping -n 3"
		cmd = exec.Command("ping", "-n", "3", "-w", "1", ipAddr)
	case "linux":
		// Linux的ping命令是 "ping -c 3"
		cmd = exec.Command("ping", "-c", "3", "-i", "1", ipAddr)
	default:
		return false, errors.New("unsupported operating system")
	}

	// 执行ping命令
	if err := cmd.Run(); err != nil {
		// 如果ping命令执行后返回错误，则认为主机不通
		return false, fmt.Errorf("ping error: %v", err)
	}

	// 如果ping命令执行成功，没有返回错误，则认为主机通畅
	return true, nil
}

// Ping
// 使用 ICMP 发送回显请求并等待回显回复（只支持ipv4）
func Ping(ip string, timeout time.Duration) (bool, error) {
	if !IsValidIP(ip) {
		return false, fmt.Errorf("invalid IP format: %s", ip)
	}
	pinger, err := ping.NewPinger(ip)
	if err != nil {
		return false, fmt.Errorf("error creating pinger for %s: %v", ip, err)
	}
	pinger.SetPrivileged(true) // 如果需要root权限，请设置为true
	pinger.Count = 1           // 发送3个Ping包
	pinger.Timeout = timeout

	err = pinger.Run() // 开始Ping
	if err != nil {
		return false, fmt.Errorf("error running pinger for %s: %v", ip, err)
	}

	stats := pinger.Statistics() // 获取Ping统计信息
	if stats.PacketsRecv > 0 {
		return true, nil
	} else {
		return false, nil
	}
}

// DetectTcpPort
// 检测Tcp端口是否开通
func DetectTcpPort(ip string, port int, timeout time.Duration) bool {
	address := fmt.Sprintf("%s:%d", ip, port)
	conn, err := net.DialTimeout("tcp", address, timeout)
	if err != nil {
		return false
	}

	// 建立后关闭连接
	defer func(conn net.Conn) {
		_ = conn.Close()
	}(conn)

	return true
}

// CalculateNetwork
// 根据给定的IP地址和子网掩码计算网络地址
// 传入 192.168.1.1 和 255.255.255.0，返回 192.168.1.0/24
func CalculateNetwork(ipAddr, subnetMask string) (string, error) {
	// 解析IP地址和子网掩码
	ip := net.ParseIP(ipAddr)
	if ip == nil {
		return "", fmt.Errorf("invalid IP address format")
	}
	mask := net.IPMask(net.ParseIP(subnetMask)[12:])
	if mask == nil {
		return "", fmt.Errorf("invalid subnet mask format")
	}

	// 计算网络地址
	network := net.IPNet{IP: ip.Mask(mask), Mask: mask}
	prefixSize, _ := mask.Size()
	return fmt.Sprintf("%s/%d", network.IP.String(), prefixSize), nil
}

// SubNetMaskToBits
// 将子网掩码转换为掩码位数
// 传入 255.255.255.0，返回 24
func SubNetMaskToBits(subnetMask string) (int, error) {
	ip := net.ParseIP(subnetMask)
	if ip == nil {
		return 0, fmt.Errorf("invalid subnet mask")
	}
	// 将IP地址转换为4字节（对于IPv4）或16字节（对于IPv6）的表示
	mask := ip.To4()
	if mask == nil {
		return 0, fmt.Errorf("invalid IPv4 subnet mask")
	}
	// 计算子网掩码中1的总数
	bits := 0
	for _, octet := range mask {
		for octet > 0 {
			bits += int(octet & 1) // 如果最低位是1，计数器增加
			octet >>= 1            // 向右移位，检查下一个位
		}
	}
	return bits, nil
}

// BitsToSubNetMask
// 将掩码位数转换为子网掩码
// 传入 24，返回 255.255.255.0
func BitsToSubNetMask(maskBits int) (string, error) {
	if maskBits < 0 || maskBits > 32 {
		return "", fmt.Errorf("invalid subnet bits: %d", maskBits)
	}
	// 根据掩码位计算子网掩码
	var mask uint32 = ^uint32(0) << (32 - maskBits)
	return fmt.Sprintf("%d.%d.%d.%d", mask>>24, (mask>>16)&0xFF, (mask>>8)&0xFF, mask&0xFF), nil
}

// IpToUint32
// 将IP地址转换为整数
// 传入 192.168.1.1，返回 3232235777
func IpToUint32(ipStr string) (uint32, error) {
	ip := net.ParseIP(ipStr)
	if ip == nil {
		return 0, fmt.Errorf("invalid IP format")
	}
	iptov4 := ip.To4()
	if iptov4 == nil {
		return 0, fmt.Errorf("not an IPv4 address")
	}
	return binary.BigEndian.Uint32(iptov4), nil
}

// Uint32ToIP
// 将整数转换为IP地址
// 传入 3232235777，返回 192.168.1.1
func Uint32ToIP(ipInt uint32) string {
	ipBytes := make([]byte, 4)
	binary.BigEndian.PutUint32(ipBytes, ipInt)
	return net.IP(ipBytes).String()
}

// ValidateAndConvertCIDR
// 验证CIDR是否合法，并转换网络地址为uint32
// 传入 192.168.1.1/24，返回 3232235776
func ValidateAndConvertCIDR(cidr string) uint32 {
	// 解析CIDR字符串，确保它是一个合法的网段
	ip, _, err := net.ParseCIDR(cidr)
	if err != nil {
		fmt.Println("Invalid CIDR:", err)
		return 0
	}

	// 将IP地址转换为uint32
	ipBytes := ip.To4() // 获取IPv4地址的4个字节表示
	if ipBytes == nil {
		fmt.Println("Invalid IPv4 address")
		return 0
	}
	ipUint32 := binary.BigEndian.Uint32(ipBytes)

	// 返回转换的uint32值和CIDR中的掩码位数
	return ipUint32
}

// IsIPInCIDR
// 判断IP地址是否在CIDR网段内
// 传入 192.168.1.1 和 192.168.0.0/16，返回 true
func IsIPInCIDR(ip string, cidr string) bool {
	_, cidrNet, err := net.ParseCIDR(cidr)
	if err != nil {
		return false
	}
	result := net.ParseIP(ip)
	return cidrNet.Contains(result)
}
